home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / tcl / minihelp.001 / minihelp~ / MiniHelp.tcl < prev   
Encoding:
Text File  |  1996-03-29  |  57.7 KB  |  1,752 lines

  1. ###############################################################
  2. # Minihelp - Help Editor
  3. # Charlie KEMPSON - charlie@siren.demon.co.uk
  4. # http://public.logica.com/~kempsonc
  5. ###############################################################
  6.  
  7. ###############################################################
  8. #    This program is free software; you can redistribute it 
  9. #    and/or modify it under the terms of the GNU General 
  10. #    Public License as published by the Free Software 
  11. #    Foundation (version 2 of the License).
  12. #
  13. #    This program is distributed in the hope that it will 
  14. #    be useful, but WITHOUT ANY WARRANTY; without even the 
  15. #    implied warranty of MERCHANTABILITY or FITNESS FOR A 
  16. #    PARTICULAR PURPOSE.  See the GNU General Public License 
  17. #    for more details.
  18. #
  19. #    For a copy of the GNU General Public License, write to the 
  20. #    Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
  21. #    MA 02139, USA.
  22. ###############################################################
  23.  
  24. ###############################################################
  25. # Set include path
  26. set GLOBAL_INCLUDE "/usr/local/lib/TkNet"
  27. #set GLOBAL_INCLUDE "/home/charlie/TKNET/usr/local/lib/TkNet"
  28.  
  29. ###############################################################
  30. # Globals for this module
  31. set BITMAP_HEIGHT       60
  32. set BITMAP_WIDTH        40
  33.  
  34. # Globals
  35. set g_selected_file ""
  36. set g_selected_file_filter ""
  37.  
  38. # Flags
  39. set gas_pages ""
  40. set gas_history ""
  41. set gb_current_page_changed 0
  42. set gb_project_changed      0
  43. set gs_current_project      ""
  44. set gs_new_project_name     ""
  45. set gs_MH_NewHelpPage        ""
  46. set gs_cut_buffer           ""
  47. set gb_show_formatted       1
  48. set gb_keep_old_text        0
  49. set gb_page_autocommit      1
  50.  
  51. # Geometry
  52. set TKNET_HELP_GEOMETRY "+200+200"
  53. set FIXED_FONT_SMALL   -*-courier-medium-r-*-*-*-*-*-*-*-*-*-*
  54. set FIXED_FONT          -*-courier-medium-r-*-*-14-*-*-*-*-*-*-*
  55. set FONT_SMALL          -adobe-helvetica-medium-r-*-*-*-*-*-*-*-*-*-*
  56. set FONT_NORMAL         -adobe-helvetica-medium-r-*-*-14-*-*-*-*-*-*-*
  57. set FONT_ITALIC         -adobe-helvetica-medium-o-*-*-14-*-*-*-*-*-*-*
  58. set FONT_BOLD           -adobe-helvetica-bold-r-*-*-14-*-*-*-*-*-*-*
  59. set BUTTON_COLOUR       Grey65
  60. set TEXT_COLOUR         White
  61. set DEFAULT_COLOUR      Grey75
  62. set RED                 Red
  63. set GREEN               ForestGreen
  64. set LOWER_BORDER        3
  65. set RIDGE_BORDER        2
  66. set DEFAULT_PADDING     5
  67.  
  68. # Set Tk/tcl global variables
  69. set tk_strictMotif      1
  70. set tcl_precision       3
  71.  
  72. ###############################################################
  73. # Set application defaults
  74.  
  75. # Fonts
  76. option add *font $FONT_NORMAL startupFile
  77.  
  78. # Highlight
  79. option add *highlightThickness 0
  80.  
  81. # Colours
  82. option add *background  $DEFAULT_COLOUR startupFile
  83. option add *Text.background  $TEXT_COLOUR startupFile
  84. option add *Entry.background  $TEXT_COLOUR startupFile
  85.  
  86. ###############################################################
  87. # The procedure to read other tcl files stored in
  88. # /usr/local/lib/TkNet/modules
  89. proc MH_SourceOther { filename } {
  90.  
  91.    # Globals
  92.    global GLOBAL_INCLUDE
  93.  
  94.    # Look in the global area for files
  95.    if [file exists "$GLOBAL_INCLUDE/modules/$filename"] {
  96.       if [catch {uplevel #0 source "$GLOBAL_INCLUDE/modules/$filename"}] {
  97.          MH_InfoDialog . "Error reading file : this doesn't look like a Tcl archive"
  98.       }
  99.    } else {
  100.       # FILE MISSING FROM /usr/local/lib/TkNet/modules
  101.       MH_InfoDialog . "File $filename missing from $GLOBAL_INCLUDE/modules."
  102.    }
  103. }
  104.  
  105. ###############################################################
  106. # Display a blocking information dialog
  107. proc MH_InfoDialog { parent string } {
  108.  
  109.    # Globals
  110.    global FONT_NORMAL RIDGE_BORDER DEFAULT_PADDING \
  111.       BITMAP_HEIGHT BITMAP_WIDTH
  112.  
  113.    # Display the string to the user
  114.    if [winfo exists .dialog] return
  115.    toplevel .dialog
  116.    wm title .dialog [wm title $parent]
  117.    wm transient .dialog .
  118. #   wm resizable .dialog 0 0 
  119.    grab current .dialog
  120.  
  121.    ###############################################################
  122.    # Create the message
  123.    frame .dialog.fr -borderwidth $RIDGE_BORDER -relief groove
  124.    pack .dialog.fr -padx $DEFAULT_PADDING -pady \
  125.       $DEFAULT_PADDING -side top -expand true -fill both
  126.    label .dialog.fr.bitmap -bitmap info -height \
  127.       $BITMAP_HEIGHT -width $BITMAP_WIDTH
  128.    label .dialog.fr.message -text $string -justify left
  129.    pack .dialog.fr.bitmap .dialog.fr.message -side left \
  130.       -anchor w
  131.  
  132.    ###############################################################
  133.    # Create the buttons below the frame
  134.    frame .dialog.button_frame -borderwidth $DEFAULT_PADDING
  135.    pack .dialog.button_frame -side bottom -fill x
  136.    button .dialog.button_frame.dismiss \
  137.        -text Dismiss -command { destroy .dialog }
  138.    pack .dialog.button_frame.dismiss
  139.  
  140.    
  141.    ###############################################################
  142.    # Bind return and space to dismiss
  143.    bind .dialog <Return> {destroy .dialog}
  144.    bind .dialog <space> {destroy .dialog}
  145.  
  146.    ###############################################################
  147.    # Centre the dialog on the parent (was widget $parent)
  148.    MH_CentreDialog .dialog
  149.  
  150.    ###############################################################
  151.    # Wait for the button to be pressed
  152.    tkwait window .dialog
  153. }
  154.  
  155. ###############################################################
  156. # Display a blocking question dialog
  157. proc MH_QuestionDialog { parent string button1 button2 } {
  158.  
  159.    # Globals
  160.    global FONT_NORMAL RIDGE_BORDER DEFAULT_PADDING \
  161.       BITMAP_HEIGHT BITMAP_WIDTH g_status
  162.  
  163.    # Initialise return status
  164.    set g_status -1
  165.  
  166.    # Display the string to the user
  167.    if [winfo exists .dialog] {return $g_status}
  168.    toplevel .dialog
  169.    wm title .dialog [wm title $parent]
  170.    wm transient .dialog .
  171. #   wm resizable .dialog 0 0 
  172.    grab current .dialog
  173.  
  174.    ###############################################################
  175.    # Create the message
  176.    frame .dialog.fr -borderwidth $RIDGE_BORDER -relief groove
  177.    pack .dialog.fr -padx $DEFAULT_PADDING -pady \
  178.       $DEFAULT_PADDING -side top -expand true -fill both
  179.    label .dialog.fr.bitmap -bitmap questhead -height \
  180.       $BITMAP_HEIGHT -width $BITMAP_WIDTH
  181.    label .dialog.fr.message -text $string -justify left
  182.    pack .dialog.fr.bitmap .dialog.fr.message -side left \
  183.       -anchor w
  184.  
  185.    ###############################################################
  186.    # Create the buttons below the frame
  187.    frame .dialog.button_frame -borderwidth $DEFAULT_PADDING
  188.    pack .dialog.button_frame -side bottom -fill x
  189.    button .dialog.button_frame.ok \
  190.       -text $button1 -command {destroy .dialog; set g_status 0}
  191.    button .dialog.button_frame.cancel \
  192.       -text $button2 -command {destroy .dialog; set g_status 1}
  193.    pack .dialog.button_frame.ok .dialog.button_frame.cancel \
  194.       -side right
  195.  
  196.    ###############################################################
  197.    # Centre the dialog on the parent
  198.    MH_CentreDialog .dialog
  199.  
  200.    ###############################################################
  201.    # Wait for the button to be pressed
  202.    tkwait variable g_status
  203.    return $g_status
  204. }
  205.  
  206. ###############################################################
  207. # Display a blocking information dialog
  208. proc MH_WorkingDialog { parent string } {
  209.  
  210.    # Globals
  211.    global FONT_NORMAL RIDGE_BORDER DEFAULT_PADDING \
  212.       BITMAP_HEIGHT BITMAP_WIDTH
  213.  
  214.    # Display the string to the user
  215.    if [winfo exists .MH_WorkingDialog] return
  216.    set window [toplevel .MH_WorkingDialog]
  217.    wm title .dialog [wm title $parent]
  218.    wm transient $window .
  219. #   wm resizable $window 0 0 
  220.    grab current $window
  221.  
  222.    ###############################################################
  223.    # Create the message
  224.    frame $window.fr -borderwidth $RIDGE_BORDER -relief groove
  225.    pack $window.fr -padx $DEFAULT_PADDING -pady \
  226.       $DEFAULT_PADDING -side top -expand true -fill both
  227.    label $window.fr.bitmap -bitmap hourglass -height \
  228.       $BITMAP_HEIGHT -width $BITMAP_WIDTH
  229.    label $window.fr.message -text $string -justify left
  230.    pack $window.fr.bitmap $window.fr.message -side left \
  231.       -anchor w
  232.  
  233.    ###############################################################
  234.    # Centre the dialog on the parent (was widget $parent)
  235.    MH_CentreDialog $window
  236.    update
  237. }
  238.  
  239. ###############################################################
  240. # Centre a window on the screen (or parent)
  241. proc MH_CentreDialog {window {position ""} {parent ""}} {
  242.  
  243.    # Withdraw dialog and update all windows
  244.    wm withdraw $window
  245.    update idletasks
  246.    set win_width [winfo reqwidth $window]
  247.    set win_height [winfo reqheight $window]
  248.  
  249.    # Read the positioning argument (pointer, widget, default)
  250.    switch -glob -- $position {
  251.       p* {
  252.          # place at POINTER (centered is $a == center)
  253.          wm geometry $window +[expr \
  254.             [winfo pointerx $window]-$win_width \
  255.             /2]+[expr [winfo pointery $window]-\
  256.             $win_height/2]
  257.       }
  258.       w* {
  259.          # center about WIDGET $parent
  260.          wm geometry $window +[expr [winfo rootx $parent]+ \
  261.             ([winfo width $parent]-$win_width)/2]+[expr \
  262.             [winfo rooty $parent]+([winfo height \
  263.             $parent]-$win_height)/2]
  264.       }
  265.       default {
  266.          wm geometry $window +[expr ([winfo screenwidth \
  267.             $window]-$win_width) / 2]+[expr ([winfo screenheight \
  268.             $window]- $win_height) / 2]
  269.       }
  270.    }
  271.  
  272.    # Now show the window
  273.    wm deiconify $window
  274. }
  275.  
  276. ###############################################################
  277. # Create a scrolled text widget
  278. proc MH_ScrolledText { f width height horiz } {
  279.  
  280.    # Global 
  281.    global FIXED_FONT_SMALL
  282.  
  283.    frame $f
  284.    # The setgrid setting allows the window to be resized.
  285.    text $f.text -width $width -height $height \
  286.       -setgrid true  -width $width -wrap word \
  287.       -yscrollcommand [list $f.yscroll set] \
  288.       -font $FIXED_FONT_SMALL
  289.    if {$horiz == 1} {
  290.       $f.text configure -xscrollcommand [list \
  291.          $f.xscroll set] -wrap none 
  292.       scrollbar $f.xscroll -orient horizontal \
  293.          -command [list $f.text xview]
  294.       pack $f.xscroll -side bottom -fill x
  295.    }
  296.    scrollbar $f.yscroll -orient vertical \
  297.       -command [list $f.text yview]
  298.    pack $f.yscroll -side right -fill y
  299.  
  300.    # The fill and expand are needed when resizing.
  301.    pack $f.text -side left -fill both -expand true
  302.    pack $f -side top -fill both -expand true
  303.    return $f.text
  304. }
  305.  
  306. ###############################################################
  307. # Create a scrolled text widget
  308. proc MH_ScrolledList { frame width height mode horiz } {
  309.  
  310.    frame $frame
  311.    # The setgrid setting allows the window to be resized.
  312.    listbox $frame.list -width $width -height $height \
  313.       -setgrid true -yscrollcommand [list $frame.yscroll set] \
  314.       -selectmode $mode
  315.    if {$horiz == 1} {
  316.       $frame.list configure -xscrollcommand [list \
  317.          $frame.xscroll set] -wrap none 
  318.       scrollbar $frame.xscroll -orient horizontal \
  319.          -command [list $frame.list xview]
  320.       pack $frame.xscroll -side bottom -fill x
  321.    }
  322.    scrollbar $frame.yscroll -orient vertical \
  323.       -command [list $frame.list yview]
  324.    pack $frame.yscroll -side right -fill y
  325.  
  326.    # The fill and expand are needed when resizing.
  327.    pack $frame.list -side left -fill both -expand true
  328.    pack $frame -side top -fill both -expand true
  329.    return $frame.list
  330. }
  331.  
  332. ###############################################################
  333. # The procedure for popping up a popup menu
  334. proc MH_PopupMenu { parent window } {
  335.  
  336.    # Get current mouse position
  337.    set x [ winfo pointerx $parent ]
  338.    set y [ winfo pointery $parent ]
  339.  
  340.    # Popup the menu
  341.    tk_popup $window $x $y
  342. }
  343.  
  344. ###############################################################
  345. # Change cursor to an hourglass and back again
  346. proc MH_WatchCursor {} {
  347.  
  348.    # Loop through children setting the cursor
  349.         foreach w [winfo children .] {
  350.                 lappend busy [list $w [lindex [$w config -cursor] 4]]
  351.         }
  352.         foreach w $busy {catch {[lindex $w 0] config -cursor watch}}
  353.         update idletasks
  354. }
  355. proc MH_NormalCursor {} {
  356.  
  357.    # Loop through children setting the cursor
  358.         foreach w [winfo children .] {
  359.                 lappend notbusy [list $w [lindex [$w config -cursor] 4]]
  360.         }
  361.         foreach w $notbusy {catch {[lindex $w 0] config -cursor hand2}}
  362.         update idletasks
  363. }
  364.  
  365.  
  366. ###############################################################
  367. # The procedure for creating images
  368. proc MH_CreateImage { file } {
  369.  
  370.    # This procedure attempts to create an image from
  371.    # the data specified in the named file.  If the 
  372.    # file is non-existant, or the image type is not
  373.    # supported, -1 is returned and a dialogue is
  374.    # displayed.
  375.  
  376.    if [file exists $file] {
  377.  
  378.       # Create the image
  379.       set name [join [list $file "_image"] ""]
  380.       if [catch {image create bitmap $name -file $file} text] {
  381.          # Not a bitmap, try pixmap
  382.          if [catch {image create pixmap $name -file $file} text] {
  383.             # Not a pixmap, try gif
  384.             if [catch {image create photo $name -file $file} text] {
  385.                # Give up!
  386.                MH_InfoDialog . "Image $file has an unrecognised type!
  387. See help on images for more information."
  388.                return -1
  389.             }
  390.          }
  391.       }
  392.       return $name
  393.    } else {
  394.       MH_InfoDialog . "File $file does not exists!"
  395.       return -1
  396.    }
  397. }
  398.  
  399. ###############################################################
  400. # The procedure for selecting a file
  401. proc MH_FileSelect { {title "Select File"} {filter "*"} } {
  402.  
  403.    # This procedure pops up a file selection box
  404.    # and returns the selected file.
  405.  
  406.    # Globals
  407.    global TEXT_COLOUR DEFAULT_PADDING RIDGE_BORDER \
  408.       g_selected_file g_selected_file_filter
  409.    set g_selected_file_filter $filter
  410.    
  411.    # Popup a selection window
  412.    set window .fileselect
  413.    if [winfo exists $window] {
  414.        # Pop it up!
  415.        wm deiconify $window
  416.        raise $window
  417.        return
  418.    }
  419.  
  420.    # Otherwise create the window
  421.    toplevel $window
  422.    wm title $window $title
  423.    wm transient $window .
  424.  
  425.    # Create a frame containing the filter
  426.    frame $window.filter_fr -borderwidth $RIDGE_BORDER -relief groove
  427.    pack $window.filter_fr -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING \
  428.       -side top -fill x
  429.    label $window.filter_fr.label -text "Filter"
  430.    entry $window.filter_fr.entry -width 15 -bg $TEXT_COLOUR \
  431.       -textvariable g_selected_file_filter
  432.    button $window.filter_fr.filter -text "Filter" -command \
  433.       MH_PopulateFileSelect 
  434.    pack $window.filter_fr.label $window.filter_fr.entry \
  435.       $window.filter_fr.filter -side left \
  436.       -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING
  437.  
  438.    # Create the directory list and file list
  439.    frame $window.list_fr
  440.    pack $window.list_fr -fill both -expand true
  441.     set dirlist [MH_ScrolledList $window.list_fr.dir_fr 0 10 browse 0]
  442.     set filelist [MH_ScrolledList $window.list_fr.file_fr 0 10 browse 0]
  443.     $dirlist configure -bg $TEXT_COLOUR
  444.     $filelist configure -bg $TEXT_COLOUR
  445.     pack forget $window.list_fr.dir_fr $window.list_fr.file_fr
  446.     pack $window.list_fr.dir_fr $window.list_fr.file_fr -side left -fill \
  447.       both -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING \
  448.       -expand true
  449.  
  450.    # Create a frame to display the current directory
  451.    frame $window.dir_fr -borderwidth $RIDGE_BORDER -relief groove
  452.    pack $window.dir_fr -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING \
  453.       -side top -fill x
  454.    label $window.dir_fr.label -text "Directory : "
  455.    label $window.dir_fr.dir 
  456.    pack $window.dir_fr.label $window.dir_fr.dir -side left \
  457.       -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING -fill x
  458.  
  459.    # Create a frame containing an entry field
  460.    frame $window.sel_fr -borderwidth $RIDGE_BORDER -relief groove
  461.    pack $window.sel_fr -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING \
  462.       -side top -fill x
  463.    label $window.sel_fr.label -text "File"
  464.    set entry [entry $window.sel_fr.entry -width 30 -bg $TEXT_COLOUR]
  465.    pack $window.sel_fr.label $window.sel_fr.entry -side left \
  466.       -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING -fill x
  467.  
  468.    # And add buttons to the window
  469.    set frame [frame $window.button_fr]
  470.    pack $frame -side bottom -fill x
  471.    button $frame.close -text Cancel -command {
  472.       destroy .fileselect
  473.       set g_selected_file ""
  474.    }
  475.    button $frame.ok -text OK -command {
  476.       set file [.fileselect.sel_fr.entry get]
  477.       set dir [pwd]
  478.       set g_selected_file "$dir/$file"
  479.       destroy .fileselect
  480.    }
  481.    bind $window.sel_fr.entry <Return> "$frame.ok invoke"
  482.    pack $frame.ok $frame.close -side right -padx $DEFAULT_PADDING -pady \
  483.       $DEFAULT_PADDING
  484.  
  485.    # Retrieve the list
  486.    MH_PopulateFileSelect
  487.  
  488.    # And now centre it on its parent
  489.    MH_CentreDialog $window widget .
  490.    focus $window.sel_fr.entry
  491.  
  492.    # Add bindings on list
  493.     bind $dirlist <Double-ButtonRelease-1> {
  494.       set page [.fileselect.list_fr.dir_fr.list get \
  495.          [.fileselect.list_fr.dir_fr.list curselection]]
  496.       if {$page == ".."} {cd ..} else {cd $page}
  497.       MH_PopulateFileSelect
  498.    }
  499.     bind $filelist <Double-ButtonRelease-1> {
  500.       set page [.fileselect.list_fr.file_fr.list get \
  501.          [.fileselect.list_fr.file_fr.list curselection]]
  502.       after 400 destroy .fileselect
  503.       set dir [pwd]
  504.       set g_selected_file "$dir/$page"
  505.    }
  506.     bind $filelist <ButtonRelease-1> {
  507.       set page [.fileselect.list_fr.file_fr.list get \
  508.          [.fileselect.list_fr.file_fr.list curselection]]
  509.       .fileselect.sel_fr.entry delete 0 end
  510.       .fileselect.sel_fr.entry insert end "$page"
  511.    }
  512.  
  513.    # Wait for destruction of window
  514.    tkwait variable g_selected_file
  515.    return $g_selected_file
  516. }
  517.  
  518. ###############################################################
  519. # The procedure for selecting a file
  520. proc MH_PopulateFileSelect { } {
  521.  
  522.    # Globals 
  523.    global g_selected_file_filter 
  524.    set filter $g_selected_file_filter
  525.  
  526.    # Retrieve new information
  527.    set files [lsort [glob -nocomplain $filter]]
  528.    set dirs [lsort [glob -nocomplain "*"]]
  529.    .fileselect.list_fr.dir_fr.list delete 0 end
  530.    .fileselect.list_fr.dir_fr.list insert end ".."
  531.    .fileselect.list_fr.file_fr.list delete 0 end
  532.  
  533.    # Loop through returned items
  534.    foreach file $files {
  535.       if ![file isdirectory $file] {
  536.          .fileselect.list_fr.file_fr.list insert end $file
  537.       }
  538.    }
  539.    foreach file $dirs {
  540.       if [file isdirectory $file] {
  541.          .fileselect.list_fr.dir_fr.list insert end $file
  542.       }
  543.    }
  544.  
  545.    # Set the current directory
  546.    .fileselect.dir_fr.dir configure -text [pwd]
  547. }
  548.  
  549. ###############################################################
  550. # Procedure to open a help file
  551. proc MH_OpenProject { } {
  552.  
  553.    # Globals
  554.    global RIDGE_BORDER DEFAULT_PADDING TEXT_COLOUR \
  555.       gb_current_page_changed gb_project_changed \
  556.       gs_current_project
  557.  
  558.    # Check for changes to the project
  559.    if {$gb_current_page_changed || $gb_project_changed} {
  560.       if [MH_QuestionDialog . "The project has changed.  Do
  561. you wish to discard changes?" "Discard" "Cancel"] {
  562.          # User requested cancel
  563.          return
  564.       }
  565.    }
  566.  
  567.    # Prompt for the project to open
  568.    set gs_current_project [MH_FileSelect "Open Project"]
  569.    if {$gs_current_project != ""} {MH_ReadProject}
  570. }
  571.  
  572. ###############################################################
  573. # Procedure to open a help file
  574. proc MH_ReadProject { } {
  575.  
  576.    # Globals
  577.    global gas_pages gs_current_project gas_history \
  578.       gt_mini_help gb_current_page_changed \
  579.       gb_project_changed
  580.  
  581.    # Get the file name
  582.    set file $gs_current_project
  583.    if {[file exists $file] == 1} {
  584.       # If current information exists, delete it.
  585.       set current_pages [info globals "gs_HELPTEXT_*"]
  586.       foreach page $current_pages {
  587.          global $page
  588.          unset $page
  589.       }
  590.  
  591.       # Blank old information
  592.       $gt_mini_help configure -state normal
  593.       $gt_mini_help delete 1.0 end
  594.       $gt_mini_help configure -state disabled
  595.       .name_fr.name configure -state normal
  596.       .name_fr.name delete 0 end
  597.       .name_fr.name configure -state disabled
  598.  
  599.       # Source the new file
  600.       if [catch {uplevel #0 "source $file"}] {
  601.          # Error reading file - probably not a help archive
  602.          MH_InfoDialog . "File does not have the correct format.
  603. Are you sure that this is a valid halp archive?"
  604.          set gs_current_project ""
  605.          return
  606.       }
  607.  
  608.       # Build up a list of new pages
  609.       set gas_pages [info globals "gs_HELPTEXT_*"]
  610.       set gas_history ""
  611.       set gb_current_page_changed 0
  612.       set gb_project_changed 0
  613.  
  614.       # Display the page selector
  615.       MH_SelectHelpPage FULL
  616.  
  617.       # Save the project name
  618.       wm title . "Edit Help - $file"
  619.  
  620.    } else {
  621.       # File does not exist
  622.       MH_InfoDialog . " File $file does not exist"
  623.       set gs_current_project ""
  624.    }
  625. }
  626.  
  627. ###############################################################
  628. # Procedure to save a help file
  629. proc MH_SaveProject { {name ""} } {
  630.  
  631.    # Globals
  632.    global gas_pages gb_project_changed gb_page_autocommit \
  633.       gb_current_page_changed gs_current_project
  634.  
  635.    # Check the name for syntactic correctness
  636.    if {[llength [split $name]] > 1 || [regexp -nocase \
  637.       {[`|!$%^&*()|~<>,]+} $name] || $name == ""} {
  638.       MH_InfoDialog . "Chosen name is not valid.
  639. The project has not been saved."
  640.       return
  641.    }
  642.  
  643.    # If project does not have a name pop
  644.    # up the save project as dialog.
  645.    if {$name == ""} {
  646.       MH_SaveProjectAs
  647.       return
  648.    }
  649.  
  650.    # If the current page has been changed, ask the user if
  651.    # (s)he wishes to save the changes to the current page
  652.    # before saving.
  653.    if {$gb_current_page_changed == 1} {
  654.       if {$gb_page_autocommit == 1 || [MH_QuestionDialog . \
  655.          "The current page has changed.  Do you wish
  656.  to save these changes with the project?" "No" "Yes"]} {
  657.          MH_SaveHelpPage
  658.       }
  659.    }
  660.  
  661.    # Open the file
  662.    if [catch {set fp [open $name w]}] {
  663.       MH_InfoDialog . "Unable to open file $name for writing"
  664.       return
  665.    }
  666.  
  667.    # Write the header
  668.    puts $fp "###############################################################
  669. #
  670. # THIS FILE WAS PRODUCES USING MINI HELP VERSION 1.0
  671. #
  672. # The file may be edited by hand but is best and most 
  673. # easily editied using the mini-help editor.
  674. #
  675. # The help text uses a minor subset of the html command
  676. # language.  The following constructs are supported:
  677. # <TITLE> Text </TITLE> - Centre's, bolds and underlines
  678. # <XREF gs_help_string_ref> Text </XREF> - Hyperlinks
  679. #
  680. # <B> Text </B> - Bold
  681. # <I> Text </I> - Italic
  682. # <TT> Text </TT> - Sans serif
  683. # <UL> Text </UL> - Underline
  684. #
  685. # <CENTER> Text </CENTER> - Centre Justify
  686. # <LEFT> Text </LEFT> - Left Justify
  687. # <RIGHT> Text </RIGHT> - Right Justify
  688. #
  689. ###############################################################
  690.  
  691. "
  692.    # Now write the help text itself
  693.    foreach page $gas_pages {
  694.       global $page
  695.       set text [eval subst \$$page]
  696.       puts $fp "global $page
  697. set $page \\
  698. \\
  699. \"$text\"
  700. "
  701.    }
  702.  
  703.    # Flush the file
  704.    flush $fp
  705.    close $fp
  706.  
  707.    # Inform the user
  708.    MH_InfoDialog . "Help saved to file $name"
  709.    set gb_project_changed 0
  710.    set gs_current_project $name
  711.    wm title . "Edit Help - $name"
  712. }
  713.  
  714. ###############################################################
  715. # Procedure to save a help file
  716. proc MH_SaveProjectAs { } {
  717.  
  718.    # Globals
  719.    global RIDGE_BORDER DEFAULT_PADDING gs_new_project_name \
  720.       TEXT_COLOUR
  721.  
  722.    # Prompt for the project to save as
  723.    set gs_new_project_name [MH_FileSelect "Save Project As..."]
  724.    if [file exists $gs_new_project_name] {
  725.       if [MH_QuestionDialog . "Are you sure you wish to overwrite
  726. file $gs_new_project_name ?" "Yes" "No"] {
  727.          MH_InfoDialog . "Help not saved"
  728.          return
  729.       }
  730.    }
  731.  
  732.    # Check validity of name
  733.    if {$gs_new_project_name != ""} {
  734.       MH_SaveProject $gs_new_project_name
  735.    } else {
  736.       MH_InfoDialog . "You must choose a name for
  737. your new help archive!"
  738.    }
  739. }
  740.  
  741. ###############################################################
  742. # Procedure to close a help file
  743. proc MH_CloseProject { b_exit } {
  744.  
  745.    # Globals
  746.    global gb_current_page_changed gb_project_changed gas_pages \
  747.       gs_current_project gs_new_project_name gs_MH_NewHelpPage \
  748.       gt_mini_help
  749.  
  750.    # Check for changes to the project
  751.    if {$gb_current_page_changed || $gb_project_changed} {
  752.       if [MH_QuestionDialog . "The project has changed.  Do
  753. you wish to discard changes?" "Discard" "Cancel"] {
  754.          # User requested cancel
  755.          return
  756.       }
  757.    }
  758.  
  759.    # Rest all variables, and destroy all globals
  760.    foreach page $gas_pages {
  761.       global $page
  762.       unset $page
  763.    }
  764.    set gas_pages ""
  765.    set gb_current_page_changed 0
  766.    set gb_project_changed      0
  767.    set gs_current_project      ""
  768.    set gs_new_project_name     ""
  769.    set gs_MH_NewHelpPage        ""
  770.    wm title . "Edit Help - <no project>"
  771.  
  772.    # Reset all user fields
  773.    $gt_mini_help configure -state normal
  774.    $gt_mini_help delete 1.0 end
  775.    $gt_mini_help configure -state disabled
  776.    .name_fr.name configure -state normal
  777.    .name_fr.name delete 0 end
  778.    .name_fr.name configure -state disabled
  779.    
  780.    # If the argument is 1, the user is trying to exit
  781.    if {$b_exit == 1} {destroy .}
  782. }
  783.  
  784. ###############################################################
  785. # The procedure to let you select a page
  786. proc MH_SelectHelpPage { type } {
  787.  
  788.    # Type may be HISTORY or FULL
  789.  
  790.    # Globals
  791.    global RIDGE_BORDER DEFAULT_PADDING TEXT_COLOUR \
  792.       gas_history gas_pages
  793.  
  794.    # Test for window
  795.    # Popup a selection window
  796.    set window .select_help
  797.    if [winfo exists $window] {
  798.        # Pop it up!
  799.        wm deiconify $window
  800.        raise $window
  801.        update
  802.        return
  803.    }
  804.  
  805.    toplevel $window
  806.    if {$type == "HISTORY"} {
  807.       wm title $window "History"
  808.       set as_list $gas_history
  809.     } else {
  810.         wm title $window "Select Page"
  811.         set as_list $gas_pages
  812.     }
  813.     wm transient $window .
  814.  
  815.     # Create a frame containing a list
  816.     frame $window.sel_fr -borderwidth $RIDGE_BORDER -relief groove
  817.     pack $window.sel_fr -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING \
  818.         -side top -fill x
  819.     set list [MH_ScrolledList $window.list_fr 0 10 browse 0]
  820.     $list configure -bg $TEXT_COLOUR
  821.     pack forget $window.list_fr
  822.     pack $window.list_fr -side top -fill both -padx $DEFAULT_PADDING \
  823.         -pady $DEFAULT_PADDING -expand true
  824.  
  825.     # Add the help pages title to the list
  826.     foreach item $as_list {
  827.         # Get the help text title for the page
  828.         set text "Unknown Help Page"
  829.         global $item
  830.         set local_text [eval subst {\$$item}]
  831.         set start [string first "<title>" $local_text]
  832.         if {$start == -1} {set start [string first "<TITLE>" $local_text]}
  833.         set end [string first "</title>" $local_text]
  834.         if {$end == -1} {set end [string first "</TITLE>" $local_text]}
  835.  
  836.         if {$start != -1} {
  837.             set start [expr [string wordend $local_text [expr $start + 1]] +1]
  838.             set end [expr [string wordstart $local_text $end] -1]
  839.             set text [string range $local_text $start $end]
  840.             set text [string trimleft $text]
  841.         } else {
  842.             MH_InfoDialog . "Error in help text (${item})!  
  843. All pages must begin with a title e.g. 
  844. <title>Contents</title> or
  845. <TITLE>Contents</TITLE>"
  846.         }
  847.         $list insert end $text
  848.     }
  849.  
  850.     # Now for a goto, close and contents button
  851.     set frame [frame $window.button_fr]
  852.     pack $frame -side bottom -fill x
  853.     button $frame.close -text Close -command "destroy $window"
  854.     button $frame.new -text New -command "destroy $window; MH_NewHelpPage"
  855.     button $frame.goto -text Goto -command "MH_SelectPageFromList $type"
  856.     bind $list <Double-ButtonRelease-1> "MH_SelectPageFromList $type"
  857.     pack $frame.close $frame.new $frame.goto -side right \
  858.         -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING
  859.  
  860.     # And now centre it on its parent
  861.     MH_CentreDialog $window widget .
  862. }
  863.  
  864. ###############################################################
  865. # The procedure to navigate backwards through the history
  866. proc MH_SelectPageFromList { type } {
  867.  
  868.    # Globals
  869.    global gas_history gas_pages
  870.  
  871.     set page [.select_help.list_fr.list curselection]
  872.     if {$page == ""} {
  873.         return
  874.     } else {
  875.  
  876.         # Type may be HISTORY or FULL
  877.         if {$type == "HISTORY"} {
  878.             set as_list $gas_history
  879.       } else {
  880.          set as_list $gas_pages
  881.       }
  882.  
  883.       set name [lindex $as_list $page]
  884.       if {$type == "HISTORY"} {set gas_history \
  885.          [lreplace $gas_history $page end]}
  886.       MH_DisplayHelpPage $name
  887.       after 400 destroy .select_help
  888.    }
  889. }
  890.  
  891. ###############################################################
  892. # The procedure to navigate backwards through the history
  893. proc MH_EditNavigateBack {} {
  894.  
  895.    # Globals
  896.    global gas_history
  897.  
  898.    # The list gas_history contains a list of all help pages
  899.    # visited.  Simply extract the second to last page, and
  900.    # delete the last item in the list, then dislpay the 
  901.    # page.
  902.    # MH_InfoDialog . $gas_history
  903.    if {[llength $gas_history] < 2} {
  904.       # Nowhere to return to
  905.       return
  906.    }
  907.    
  908.    # Get the last page
  909.    set help [lindex $gas_history [expr [llength $gas_history] - 2]]
  910.  
  911.    # Delete the two last items (note that one of them is recreated
  912.    # when we call MH_DisplayHelpPage).
  913.    set gas_history [lreplace $gas_history [expr [llength $gas_history] \
  914.       - 2] end]
  915.  
  916.    # And show the help page
  917.    MH_DisplayHelpPage $help
  918. }
  919.  
  920. ###############################################################
  921. # Procedure for displaying a help page
  922. proc MH_DisplayHelpPage { text } {
  923.  
  924.    # Globals
  925.    global gt_mini_help gas_pages gb_current_page_changed \
  926.       gas_history
  927.  
  928.    # Check for the existence of the page before going
  929.    # ahead...
  930.    if {[info globals $text] == ""} {
  931.       MH_InfoDialog . "Page does not exist!"
  932.       return
  933.    }
  934.  
  935.    # Display the associated help text
  936.    $gt_mini_help configure -state normal
  937.    $gt_mini_help delete 1.0 end
  938.    global $text 
  939.    $gt_mini_help insert end [eval subst \$$text]
  940.    # Parse the help (0=Edit rather than run time)
  941.    MH_ParseHelp 0
  942.    set gb_current_page_changed 0
  943.  
  944.    # Set the focus
  945.    focus $gt_mini_help
  946.  
  947.    # Display the page title in the entry
  948.    .name_fr.name configure -state normal
  949.    .name_fr.name delete 0 end
  950.    .name_fr.name insert end [string range $text 12 end]
  951.    .name_fr.name configure -state disabled
  952.    .name_fr.save configure -state disabled
  953.  
  954.    # Add to the history list (removing any other references to
  955.    # the page on the way - there will be at most one given the
  956.    # nature of the check)
  957.    set item [lsearch -exact $gas_history $text]
  958.    if {$item != -1} {set gas_history [lreplace $gas_history $item $item]}
  959.    lappend gas_history $text
  960. }
  961.  
  962. ###############################################################
  963. # Procedure for displaying a new help page
  964. proc MH_NewHelpPage { } {
  965.  
  966.    # If the variable keep_old_text is set, then 
  967.    # the text that is currently being displayed
  968.    # is retained.
  969.  
  970.    # Globals
  971.    global RIDGE_BORDER DEFAULT_PADDING gs_MH_NewHelpPage \
  972.       gt_mini_help gas_pages TEXT_COLOUR gb_keep_old_text \
  973.       gas_history
  974.  
  975.    # Popup a selection window
  976.    set window .new_page
  977.    if [winfo exists $window] {
  978.        # Pop it up!
  979.        wm deiconify $window
  980.        raise $window
  981.        return
  982.    }
  983.  
  984.    # Otherwise create the window
  985.    toplevel $window
  986.    wm title $window "New Help Page"
  987.    wm transient $window .
  988.  
  989.    # Create a frame containing a list and an entry field
  990.    frame $window.sel_fr -borderwidth $RIDGE_BORDER -relief groove
  991.    pack $window.sel_fr -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING \
  992.       -side top -fill x
  993.    label $window.sel_fr.label -text "Page Name"
  994.    entry $window.sel_fr.entry -width 30 -bg $TEXT_COLOUR -textvariable \
  995.       gs_MH_NewHelpPage
  996.    pack $window.sel_fr.label $window.sel_fr.entry -side left \
  997.       -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING
  998.  
  999.    # And add buttons to the window
  1000.    set frame [frame $window.button_fr]
  1001.    pack $frame -side bottom -fill x
  1002.    button $frame.close -text Cancel -command "wm withdraw $window"
  1003.    button $frame.ok -text OK -command {
  1004.       # Check the name for syntactic correctness
  1005.       if {[llength [split $gs_MH_NewHelpPage]] > 1 || [regexp -nocase \
  1006.          {[`"#;:',.?/\|!$%^&*()|~<>,]+} $gs_MH_NewHelpPage] ||
  1007.          $gs_MH_NewHelpPage == ""} {
  1008.          MH_InfoDialog . "Chosen name is not valid.  Please input 
  1009. another name.  It must contain only alphanumeric
  1010. characters."
  1011.       } else {
  1012.          # Create a new global
  1013.          set variable "gs_HELPTEXT_$gs_MH_NewHelpPage"
  1014.          global $variable
  1015.          set $variable ""
  1016.          lappend gas_pages $variable
  1017.          lappend gas_history $variable
  1018.  
  1019.          # Clear the text area
  1020.          $gt_mini_help configure -state normal
  1021.          if {$gb_keep_old_text == 0} {
  1022.             $gt_mini_help delete 1.0 end
  1023.          } else {
  1024.             # Reset flag
  1025.             set gb_keep_old_text 0
  1026.          }
  1027.  
  1028.          # Display the page title in the entry
  1029.          .name_fr.name configure -state normal
  1030.          .name_fr.name delete 0 end
  1031.          .name_fr.name insert end $gs_MH_NewHelpPage
  1032.          .name_fr.name configure -state disabled
  1033.  
  1034.          # Set the focus
  1035.          focus $gt_mini_help
  1036.  
  1037.          # Page should be saved (project has changed)
  1038.          .name_fr.save configure -state normal
  1039.          set gb_current_page_changed 1
  1040.  
  1041.          # Withdraw this window
  1042.          wm withdraw .new_page
  1043.       }
  1044.    }
  1045.    bind $window.sel_fr.entry <Return> "$frame.ok invoke"
  1046.    pack $frame.ok $frame.close -side right -padx $DEFAULT_PADDING -pady \
  1047.       $DEFAULT_PADDING
  1048.  
  1049.    # And now centre it on its parent
  1050.    MH_CentreDialog $window widget .
  1051.    focus $window.sel_fr.entry
  1052. }
  1053.  
  1054. ###############################################################
  1055. # The procedure for finding tags in the help
  1056. proc MH_ShowHyperMenu { tag } {
  1057.  
  1058.    # Globals
  1059.    global gt_mini_help
  1060.  
  1061.    # Create the menu - Check for existence
  1062.    set window .hyper_popup_menu
  1063.    if [winfo exists $window] {destroy $window}
  1064.  
  1065.    # Find the start and end of the current tag
  1066.    set x [ winfo pointerx $gt_mini_help ]
  1067.    set y [ winfo pointery $gt_mini_help ]
  1068.    set curpos [$gt_mini_help index @$x,$y]
  1069.    set ranges [$gt_mini_help tag ranges $tag]
  1070.    set list_len [llength $ranges]
  1071.    for {set count 0} {$count < $list_len} {incr count 2} {
  1072.       if {$curpos >= [lindex $ranges $count]} {
  1073.          set start [lindex $ranges $count]
  1074.          set end [lindex $ranges [expr $count + 1]]
  1075.          #MH_InfoDialog . "Tag found $start $end"
  1076.       }
  1077.    }
  1078.  
  1079.    # Create the popup menu
  1080.    menu .hyper_popup_menu -tearoff 0
  1081.       $window add checkbutton -label [string range $tag 12 end] \
  1082.          -indicatoron False
  1083.       $window add separator
  1084.       $window add command -label "Open Link" -command "MH_OpenLink \
  1085.          $tag" -underline 0
  1086.       $window add command -label "Bind Link" -command "MH_BindLink \
  1087.          $tag $start $end" -underline 0
  1088.  
  1089.    # Now popup the window in place
  1090.    MH_PopupMenu . $window
  1091. }
  1092.  
  1093. ###############################################################
  1094. # The procedure for finding tags in the help
  1095. proc MH_BindLink { tag start end } {
  1096.  
  1097.    # Globals
  1098.    global gas_pages RIDGE_BORDER \
  1099.       DEFAULT_PADDING TEXT_COLOUR gt_mini_help
  1100.  
  1101.    # Test for NULL arguments.  If so, use current
  1102.    # selection...
  1103.    if {$start == ""} {
  1104.       # MH_InfoDialog . "Using current selection"
  1105.       if [catch {$gt_mini_help get sel.first}] {return}
  1106.       set start [$gt_mini_help index sel.first]
  1107.       set end [$gt_mini_help index sel.last]
  1108.  
  1109.       # Ensure that the current selection has not
  1110.       # already got a hyperlink tag
  1111.       MH_RemoveTags XREF
  1112.    }
  1113.    if {$tag == ""} {set tag NONE}
  1114.  
  1115.    # Test for window
  1116.    # Popup a selection window
  1117.    set window .bind_hyperlink
  1118.    if [winfo exists $window] {destroy $window}
  1119.    toplevel $window
  1120.    wm title $window "Select Hyperlink"
  1121.    wm transient $window .
  1122.  
  1123.    # Create a frame containing a list
  1124.    frame $window.sel_fr -borderwidth $RIDGE_BORDER -relief groove
  1125.    pack $window.sel_fr -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING \
  1126.       -side top -fill x
  1127.    set list [MH_ScrolledList $window.list_fr 0 10 browse 0]
  1128.    $list configure -bg $TEXT_COLOUR
  1129.    pack forget $window.list_fr
  1130.    pack $window.list_fr -side top -fill both -padx $DEFAULT_PADDING \
  1131.       -pady $DEFAULT_PADDING -expand true
  1132.  
  1133.    # MH_InfoDialog . $gas_pages
  1134.    # Add the help pages title to the list
  1135.    foreach item $gas_pages {
  1136.       # Get the help text title for the page
  1137.       set text "Unknown Help Page"
  1138.       global $item
  1139.       set local_text [eval subst {\$$item}]
  1140.       set p1 [string first "<title>" $local_text]
  1141.       if {$p1 == -1} {set p1 [string first "<TITLE>" $local_text]}
  1142.       set p2 [string first "</title>" $local_text]
  1143.       if {$p2 == -1} {set p2 [string first "</TITLE>" $local_text]}
  1144.  
  1145.       if {$p1 != -1} {
  1146.          set p1 [expr [string wordend $local_text [expr $p1 + 1]] +1]
  1147.          set p2 [expr [string wordstart $local_text $p2] -1]
  1148.          set text [string range $local_text $p1 $p2]
  1149.          set text [string trimleft $text]
  1150.       } else {
  1151.          MH_InfoDialog . "Error in help text (${item})!  
  1152. All pages must begin with a title e.g. 
  1153. <title>Contents</title> or
  1154. <TITLE>Contents</TITLE>"
  1155.       }
  1156.       set page [string range $item 12 end]
  1157.       $list insert end "$text - $page"
  1158.    }
  1159.  
  1160.    # Now for a goto, close and contents button
  1161.    set frame [frame $window.button_fr]
  1162.    pack $frame -side bottom -fill x
  1163.    button $frame.cancel -text Cancel -command "destroy $window"
  1164.    button $frame.bind -text OK -command "MH_Create_Link $tag $start $end"
  1165.    pack $frame.cancel $frame.bind -side right \
  1166.       -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING
  1167.  
  1168.    # And now centre it on its parent
  1169.    MH_CentreDialog $window widget .
  1170. }
  1171.  
  1172. ###############################################################
  1173. # The procedure for opening a tag in the help
  1174. proc MH_Create_Link { tag start end } {
  1175.  
  1176.    # Globals
  1177.    global gt_mini_help gas_pages RED GREEN FONT_BOLD \
  1178.       gb_current_page_changed gb_project_changed
  1179.  
  1180.    set page [.bind_hyperlink.list_fr.list curselection]
  1181.    if {$page == ""} {
  1182.       return
  1183.    } else {
  1184.       set name [lindex $gas_pages $page]
  1185.       if {$tag != "NONE"} {
  1186.          $gt_mini_help tag remove $tag $start $end
  1187.       }
  1188.       $gt_mini_help tag add $name $start $end
  1189.       $gt_mini_help tag configure $name -foreground \
  1190.          $GREEN -font $FONT_BOLD
  1191.       $gt_mini_help tag bind $name <Enter> \
  1192.          "$gt_mini_help tag configure $name -foreground $RED"
  1193.       $gt_mini_help tag bind $name <Leave> \
  1194.          "$gt_mini_help tag configure $name -foreground $GREEN"
  1195.       $gt_mini_help tag bind $name <ButtonPress> "MH_ShowHyperMenu $name"
  1196.  
  1197.       # Page has changed
  1198.       set gb_project_changed      1
  1199.       set gb_current_page_changed 1
  1200.       .name_fr.save configure -state normal
  1201.  
  1202.       # Destroy the popup
  1203.       destroy .bind_hyperlink
  1204.    }
  1205. }
  1206.  
  1207. ###############################################################
  1208. # The procedure for opening a tag in the help
  1209. proc MH_OpenLink { tag } {
  1210.  
  1211.    # Globals
  1212.    global gb_current_page_changed gb_page_autocommit
  1213.  
  1214.    # Check for changed
  1215.    if {$gb_current_page_changed == 0 || $gb_page_autocommit == 1} {
  1216.       MH_SaveHelpPage
  1217.       MH_DisplayHelpPage $tag
  1218.    } else {
  1219.       if ![MH_QuestionDialog . "Help text on this page has changed!" \
  1220.          "Discard Changes" "Cancel"] {
  1221.          MH_DisplayHelpPage $tag
  1222.       }
  1223.    }
  1224. }
  1225.  
  1226. ###############################################################
  1227. # The procedure for finding tags in the help
  1228. proc MH_RenamePage { } {
  1229.  
  1230.    # Global
  1231.    global gb_keep_old_text gas_history gas_pages
  1232.  
  1233.    # Popup a warning dialogue
  1234.    MH_InfoDialog . "All references to this page must be regenerated!"
  1235.  
  1236.    # All we need do is to call MH_NewHelpPage, asking the
  1237.    # routine to retain the current information.  Then
  1238.    # we delete the old variable reference.
  1239.    set gb_keep_old_text 1
  1240.    set name [.name_fr.name get]
  1241.    set name "gs_HELPTEXT_$name"
  1242.    global $name
  1243.    unset $name
  1244.  
  1245.    # Delete from history, and delete from list of pages
  1246.    set location [lsearch -exact $gas_pages $name]
  1247.    if {$location != -1} {
  1248.       set gas_pages [lreplace $gas_pages $location $location]
  1249.    }
  1250.    set location [lsearch -exact $gas_history $name]
  1251.    if {$location != -1} {
  1252.       set gas_history [lreplace $gas_history $location $location]
  1253.    }
  1254.  
  1255.    # Create the new page
  1256.    MH_NewHelpPage
  1257.    # Fill the field with default information, and
  1258.    # disable the cancel button
  1259.    wm title .new_page "Rename Page"
  1260.    .new_page.sel_fr.entry delete 0 end
  1261.    .new_page.sel_fr.entry insert end [.name_fr.name get]
  1262.    pack forget .new_page.button_fr.close
  1263. }
  1264.  
  1265. ###############################################################
  1266. # The procedure for finding tags in the help
  1267. proc MH_Create_Help { } {
  1268.  
  1269.    # Globals
  1270.    global gt_mini_help search FONT_BOLD FONT_ITALIC \
  1271.       FIXED_FONT TEXT_COLOUR
  1272.  
  1273.    # Format list
  1274.    set format_list [list TITLE BOLD ITALIC FIXED UNDERLINE CENTER \
  1275.       LEFT RIGHT]
  1276.  
  1277.    # Keyworks
  1278.    set TITLE "TITLE"
  1279.    set BOLD  "B"
  1280.    set ITALIC "I"
  1281.    set FIXED "TT"
  1282.    set UNDERLINE "U"
  1283.    set CENTER "CENTER"
  1284.    set LEFT "LEFT"
  1285.    set RIGHT "RIGHT"
  1286.  
  1287.    # Loop round the declared types
  1288.    foreach type $format_list {
  1289.       # Note that location here is a two element list
  1290.       set location [$gt_mini_help tag nextrange $type 1.0]
  1291.       set format [eval subst \$$type]
  1292.       # MH_InfoDialog . $location
  1293.       while {$location != ""} {
  1294.          # Replace the tagged area with the formatting
  1295.          # instructions
  1296.          $gt_mini_help tag remove $type [lindex $location 0] \
  1297.             [lindex $location 1]
  1298.          $gt_mini_help insert [lindex $location 1] "</$format>"
  1299.          $gt_mini_help insert [lindex $location 0] "<$format>"
  1300.          set location [$gt_mini_help tag nextrange $type 1.0]
  1301.       }
  1302.    }
  1303.  
  1304.    # Now save the hyperlinks - get a tag list and extract
  1305.    # all non-hyperlink tags.
  1306.    set tags [$gt_mini_help tag names]
  1307.    lappend format_list sel
  1308.    foreach format $format_list {
  1309.       while {[lsearch -exact $tags $format] != -1} {
  1310.          set position [lsearch -exact $tags $format]
  1311.          set tags [lreplace $tags $position $position]
  1312.       }
  1313.    }
  1314.    #MH_InfoDialog . $tags
  1315.    foreach type $tags {
  1316.       # For each range in question, tag the selection
  1317.       set location [$gt_mini_help tag nextrange $type 1.0]
  1318.       # MH_InfoDialog . $location
  1319.       while {$location != ""} {
  1320.          # Replace the tagged area with the formatting
  1321.          # instructions
  1322.          $gt_mini_help tag remove $type [lindex $location 0] \
  1323.             [lindex $location 1]
  1324.          $gt_mini_help insert [lindex $location 1] "</XREF>"
  1325.          $gt_mini_help insert [lindex $location 0] "<XREF $type>"
  1326.          set location [$gt_mini_help tag nextrange $type 1.0]
  1327.       }
  1328.    }
  1329.  
  1330.    # Disable text by default
  1331.    $gt_mini_help configure -state disabled
  1332. }
  1333.  
  1334. ###############################################################
  1335. # The procedure for finding tags in the help
  1336. proc MH_SaveHelpPage { } {
  1337.  
  1338.    # Globals
  1339.    global gt_mini_help gb_current_page_changed \
  1340.       gb_show_formatted
  1341.  
  1342.    # Create the tagged text
  1343.    MH_Create_Help
  1344.  
  1345.    # Now save to the variable
  1346.    set name [.name_fr.name get]
  1347.    set name "gs_HELPTEXT_$name"
  1348.    global $name
  1349.    set text [$gt_mini_help get 1.0 end]
  1350.    set $name $text
  1351.  
  1352.    # If show is true, redisplay the text in formatted form.
  1353.    # Otherwise, leave unformatted.
  1354.    if {$gb_show_formatted == 1} {
  1355.       # Now redisplay the text and disable the save button
  1356.       $gt_mini_help configure -state normal
  1357.       MH_ParseHelp 0
  1358.    }
  1359.  
  1360.    # Reset status
  1361.    .name_fr.save configure -state disabled
  1362.    set gb_current_page_changed 0
  1363. }
  1364.  
  1365. ###############################################################
  1366. # The procedure for finding tags in the help
  1367. proc MH_DeleteHelpPage { name } {
  1368.  
  1369.    # Globals
  1370.    global gas_pages gt_mini_help gb_current_page_changed \
  1371.       gb_project_changed
  1372.    set page "gs_HELPTEXT_$name"
  1373.    global $page
  1374.    
  1375.    # Ask the user for confirmation
  1376.    if ![MH_QuestionDialog . "Do you really want to delete page '$name'?" \
  1377.       "Delete" "Cancel"] {
  1378.       # Perform deletion.
  1379.       unset $page
  1380.       set item [lsearch -exact $gas_pages $page]
  1381.       set gas_pages [lreplace $gas_pages $item $item]
  1382.       set gas_history [lreplace $gas_history $item $item]
  1383.  
  1384.       # And blank out the edit areas of the screen
  1385.       $gt_mini_help configure -state normal
  1386.       $gt_mini_help delete 1.0 end
  1387.       $gt_mini_help configure -state disabled
  1388.       set gb_current_page_changed 0
  1389.       set gb_project_changed 1
  1390.  
  1391.       # Display the page title in the entry
  1392.       .name_fr.name configure -state normal
  1393.       .name_fr.name delete 0 end
  1394.       .name_fr.name configure -state disabled
  1395.       .name_fr.save configure -state disabled
  1396.    }
  1397. }
  1398.  
  1399. ###############################################################
  1400. # The procedure to goto a specified page from the history
  1401. proc MH_CopyText { delete } {
  1402.  
  1403.    # Global
  1404.    global gt_mini_help gs_cut_buffer
  1405.  
  1406.    # Copy the selected text into the cut buffer, then
  1407.    # delete if the flag 'delete' is set.
  1408.    if [catch {$gt_mini_help get sel.first}] {return}
  1409.    set gs_cut_buffer [$gt_mini_help get sel.first sel.last]
  1410.  
  1411.    # And delete/allow a save if data deleted
  1412.    if {$delete == 1} { 
  1413.       $gt_mini_help delete sel.first sel.last
  1414.       set gb_project_changed      1
  1415.       set gb_current_page_changed 1
  1416.       .name_fr.save configure -state normal
  1417.    }
  1418. }
  1419.  
  1420. ###############################################################
  1421. # The procedure to goto a specified page from the history
  1422. proc MH_PasteText { } {
  1423.  
  1424.    # Global
  1425.    global gt_mini_help gs_cut_buffer
  1426.  
  1427.    # Perform paste if data exists in the cut buffer
  1428.    if {$gs_cut_buffer != ""} {
  1429.       set position [$gt_mini_help index insert]
  1430.       $gt_mini_help insert $position $gs_cut_buffer
  1431.    }
  1432. }
  1433.  
  1434. ###############################################################
  1435. # The procedure to add a tag to the current selection
  1436. proc MH_AddTag { type } {
  1437.  
  1438.    # Globals
  1439.    global gt_mini_help search FONT_BOLD FONT_ITALIC \
  1440.       FIXED_FONT TEXT_COLOUR RED GREEN gb_project_changed \
  1441.       gb_current_page_changed
  1442.  
  1443.    # Format list
  1444.    set format_list [list TITLE BOLD ITALIC FIXED UNDERLINE CENTER \
  1445.       LEFT RIGHT]
  1446.  
  1447.    # If the input argument is not in this list then it is 
  1448.    # not a valid type.
  1449.    if {[lsearch -exact $format_list $type] == -1} {
  1450.       MH_InfoDialog . "Invalid/unknown tag type specified!"
  1451.       return
  1452.    }
  1453.  
  1454.    # Keyworks and formatting
  1455.    set TITLE "TITLE"
  1456.    set TITLE_FORMAT "-font $FONT_BOLD -underline True -justify center"
  1457.    set BOLD  "B"
  1458.    set BOLD_FORMAT "-font $FONT_BOLD"
  1459.    set ITALIC "I"
  1460.    set ITALIC_FORMAT "-font $FONT_ITALIC"
  1461.    set FIXED "TT"
  1462.    set FIXED_FORMAT "-font $FIXED_FONT"
  1463.    set UNDERLINE "U"
  1464.    set UNDERLINE_FORMAT "-underline True"
  1465.    set CENTER "CENTER"
  1466.    set CENTER_FORMAT "-justify center"
  1467.    set LEFT "LEFT"
  1468.    set LEFT_FORMAT "-justify left"
  1469.    set RIGHT "RIGHT"
  1470.    set RIGHT_FORMAT "-justify right"
  1471.  
  1472.    # Get the selected text, and format with the 
  1473.    # characteristic given, flagging the block with
  1474.    # the tag.  Check for a selection first.
  1475.    if [catch {$gt_mini_help get sel.first}] {return}
  1476.  
  1477.    # Certain tags preclude other tags (e.g. justification)
  1478.    if {$type == "CENTER" || $type == "LEFT" || $type == "RIGHT"} {
  1479.       MH_RemoveTags JUSTIFY
  1480.    }
  1481.  
  1482.    # Add the new tag type
  1483.    $gt_mini_help tag add $type sel.first sel.last
  1484.    set format [eval subst \$${type}_FORMAT]
  1485.    eval $gt_mini_help tag configure $type $format
  1486.    $gt_mini_help tag raise $type
  1487.  
  1488.    # And allow a save
  1489.    set gb_project_changed      1
  1490.    set gb_current_page_changed 1
  1491.    .name_fr.save configure -state normal
  1492. }
  1493.  
  1494. ###############################################################
  1495. # The procedure to remove all tags from the current selection
  1496. proc MH_RemoveTags { type } {
  1497.  
  1498.    # Global
  1499.    global gt_mini_help FIXED_FONT gb_project_changed \
  1500.       gb_current_page_changed
  1501.  
  1502.    # Allowable values for type are:
  1503.    # XREF - Hyperlink references
  1504.    # CHARACTER - Character/font formatting
  1505.    # JUSTIFY - Justification
  1506.    # ALL - All formatting
  1507.  
  1508.    set as_character [list BOLD UNDERLINE TITLE ITALIC FIXED]
  1509.    set as_justify [list CENTER LEFT RIGHT]
  1510.    set as_non_xref [list BOLD UNDERLINE TITLE ITALIC FIXED \
  1511.       CENTER LEFT RIGHT sel]
  1512.    set delete_xref 0
  1513.    set al_del_list ""
  1514.  
  1515.    # Determine what needs to be done
  1516.    switch -exact $type {
  1517.       XREF {set delete_xref 1}
  1518.       CHARACTER {set al_del_list $as_character}
  1519.       JUSTIFY {set al_del_list $as_justify}
  1520.       ALL {set al_del_list [list [join $as_character $as_justify]]
  1521.          set delete_xref 1}
  1522.       default {
  1523.          MH_InfoDialog . "Error: Unrecognised clear command"
  1524.          return
  1525.       }
  1526.    }
  1527.  
  1528.    # Get the selected text, and unformat
  1529.    if [catch {$gt_mini_help get sel.first}] {return}
  1530.    set this [$gt_mini_help index sel.first]
  1531.    set last [$gt_mini_help index sel.last]
  1532.    while {$this != $last} {
  1533.  
  1534.       # Delete selected formatting commands
  1535.       foreach tag $al_del_list {
  1536.          #MH_InfoDialog . "Removing $tag from position $this"
  1537.          $gt_mini_help tag remove $tag $this
  1538.       }
  1539.       # If delete_xref selected find the xrefs and delete
  1540.       if {$delete_xref == 1} {
  1541.          set tags [$gt_mini_help tag names $this]
  1542.          foreach tag $as_non_xref {
  1543.             set loc [lsearch -exact $tags $tag]
  1544.             if {$loc != -1} {set tags [lreplace $tags $loc $loc]}
  1545.          }
  1546.          foreach xref $tags {
  1547.             #MH_InfoDialog . "Removing xref $tag from position $this"
  1548.             $gt_mini_help tag remove $xref $this
  1549.          }
  1550.       }
  1551.  
  1552.       # Increment to the next character
  1553.       set this [$gt_mini_help index "$this + 1 chars"]
  1554.    }
  1555.  
  1556.    # And allow a save
  1557.    set gb_project_changed      1
  1558.    set gb_current_page_changed 1
  1559.    .name_fr.save configure -state normal
  1560. }
  1561.  
  1562. ###############################################################
  1563. # Show the main interface
  1564. ###############################################################
  1565.  
  1566. # Source other files
  1567. MH_SourceOther MiniHelp_Runtime.tcl
  1568.  
  1569. # Create the mini-help screen
  1570. wm title . "Edit Help - <no project>"
  1571. wm geometry . $TKNET_HELP_GEOMETRY
  1572. wm protocol . WM_DELETE_WINDOW "MH_CloseProject 1"
  1573.  
  1574. ###########################################################################
  1575. # Create Menu Bar
  1576. frame .mbar -relief raised -bd 2
  1577. pack .mbar -side top -fill x
  1578.  
  1579. # Create the buttons   
  1580. menubutton .mbar.file -text File -underline 0 -menu .mbar.file.menu
  1581. menubutton .mbar.edit -text Edit -underline 0 -menu .mbar.edit.menu
  1582. menubutton .mbar.format -text Format -underline 0 -menu .mbar.format.menu
  1583. menubutton .mbar.justify -text Justify -underline 0 -menu .mbar.justify.menu
  1584. menubutton .mbar.page -text Page -underline 0 -menu .mbar.page.menu
  1585. menubutton .mbar.navigate -text Navigate -underline 0 -menu .mbar.navigate.menu
  1586. menubutton .mbar.options -text Options -underline 0 -menu .mbar.options.menu
  1587. pack .mbar.file .mbar.edit .mbar.format .mbar.justify .mbar.page \
  1588.    .mbar.navigate .mbar.options -side left
  1589.  
  1590. # Create each menu item
  1591. menu .mbar.file.menu -tearoff 0
  1592.    .mbar.file.menu add command -label "Open" -command \
  1593.       "MH_OpenProject" -underline 0 -accelerator "Ctrl-O"
  1594.    .mbar.file.menu add command -label "Close" -command \
  1595.       "MH_CloseProject 0" -underline 0
  1596.    .mbar.file.menu add separator
  1597.    .mbar.file.menu add command -label "Save" -command \
  1598.       {MH_SaveProject $gs_current_project} -underline 0
  1599.    .mbar.file.menu add command -label "Save As..." -command "MH_SaveProjectAs" -underline 0
  1600.    .mbar.file.menu add separator
  1601.    .mbar.file.menu add command -label "Exit" -command "MH_CloseProject 1" -underline 0
  1602. menu .mbar.edit.menu -tearoff 0
  1603.    .mbar.edit.menu add command -label "Cut" -command \
  1604.       "MH_CopyText 1" -underline 2 -accelerator "Ctrl-X"
  1605.    .mbar.edit.menu add command -label "Copy" -command \
  1606.       "MH_CopyText 0" -underline 0 -accelerator "Ctrl-C"
  1607.    .mbar.edit.menu add command -label "Paste" -command \
  1608.       "MH_PasteText" -underline 0 -accelerator "Ctrl-V"
  1609.    .mbar.edit.menu add separator
  1610.    .mbar.edit.menu add command -label "Remove Link" -command \
  1611.       "MH_RemoveTags XREF" -underline 0
  1612.    .mbar.edit.menu add command -label "Remove Formatting" -command \
  1613.       "MH_RemoveTags CHARACTER" -underline 0
  1614.    .mbar.edit.menu add command -label "Remove Justification" -command \
  1615.       "MH_RemoveTags JUSTIFY" -underline 0
  1616.    .mbar.edit.menu add command -label "Remove All" -command \
  1617.       "MH_RemoveTags ALL" -underline 0
  1618. menu .mbar.format.menu -tearoff 0
  1619.    .mbar.format.menu add command -label Bold -command "MH_AddTag BOLD" \
  1620.       -underline 0 -accelerator "Ctrl-B"
  1621.    .mbar.format.menu add command -label Italic -command \
  1622.       "MH_AddTag ITALIC" -underline 0 -accelerator "Ctrl-I"
  1623.    .mbar.format.menu add command -label Underline -command \
  1624.       "MH_AddTag UNDERLINE" -underline 0 -accelerator "Ctrl-U"
  1625.    .mbar.format.menu add command -label Serif -command \
  1626.       "MH_AddTag FIXED" -underline 0 -accelerator "Ctrl-S"
  1627.    .mbar.format.menu add separator
  1628.    .mbar.format.menu add command -label Title -command \
  1629.       "MH_AddTag TITLE" -underline 0 -accelerator "Ctrl-T"
  1630.    .mbar.format.menu add command -label Hyperlink... -command \
  1631.       {MH_BindLink "" "" ""} -underline 0 -accelerator "Ctrl-L"
  1632. menu .mbar.justify.menu -tearoff 0
  1633.    .mbar.justify.menu add command -label Centre -command \
  1634.       "MH_AddTag CENTER" -underline 0
  1635.    .mbar.justify.menu add command -label Left -command \
  1636.       "MH_AddTag LEFT" -underline 0
  1637.    .mbar.justify.menu add command -label Right -command \
  1638.       "MH_AddTag RIGHT" -underline 0
  1639. menu .mbar.page.menu -tearoff 0
  1640.    .mbar.page.menu add command -label New -command {
  1641.       if {$gb_current_page_changed == 0 || $gb_page_autocommit == 1} {
  1642.          MH_SaveHelpPage
  1643.          MH_NewHelpPage 
  1644.       } else {
  1645.          if ![MH_QuestionDialog . "Help text on this page has changed!" \
  1646.             "Discard Changes" "Cancel"] {
  1647.             MH_NewHelpPage 
  1648.          }
  1649.       }
  1650.    } -underline 0
  1651.    .mbar.page.menu add command -label "Rename ..." -command \
  1652.       {MH_RenamePage} -underline 0
  1653.    .mbar.page.menu add command -label Delete -command {
  1654.       set name [.name_fr.name get]
  1655.       if {$name != ""} {
  1656.          MH_DeleteHelpPage $name
  1657.       }
  1658.    } -underline 0
  1659.    .mbar.page.menu add separator
  1660.    .mbar.page.menu add checkbutton -label "Display Formatted" -command {
  1661.       if {$gb_show_formatted == 1} {
  1662.          MH_ParseHelp 0
  1663.       } else {
  1664.          MH_Create_Help
  1665.       }
  1666.    } -variable gb_show_formatted
  1667. menu .mbar.navigate.menu -tearoff 0
  1668.    .mbar.navigate.menu add command -label "Previous Page" -command {
  1669.       if {$gb_current_page_changed == 0 || $gb_page_autocommit == 1} {
  1670.          MH_SaveHelpPage
  1671.          MH_EditNavigateBack
  1672.       } else {
  1673.          if ![MH_QuestionDialog . "Help text on this page has changed!" \
  1674.             "Discard Changes" "Cancel"] {
  1675.             MH_EditNavigateBack
  1676.          }
  1677.       }
  1678.    } -underline 0 -accelerator "Ctrl-P"
  1679.    .mbar.navigate.menu add command -label "History ..." -command {
  1680.       if {$gb_current_page_changed == 0 || $gb_page_autocommit == 1} {
  1681.          MH_SaveHelpPage
  1682.          MH_SelectHelpPage HISTORY
  1683.       } else {
  1684.          if ![MH_QuestionDialog . "Help text on this page has changed!" \
  1685.             "Discard Changes" "Cancel"] {
  1686.             MH_SelectHelpPage HISTORY
  1687.          }
  1688.       }
  1689.    } -underline 0 -accelerator "Ctrl-H"
  1690.    .mbar.navigate.menu add command -label "Select Page ..." -command {
  1691.       if {$gb_current_page_changed == 0 || $gb_page_autocommit == 1} {
  1692.          MH_SaveHelpPage
  1693.          MH_SelectHelpPage FULL
  1694.       } else {
  1695.          if ![MH_QuestionDialog . "Help text on this page has changed!" \
  1696.             "Discard Changes" "Cancel"] {
  1697.             MH_SelectHelpPage FULL
  1698.          }
  1699.       }
  1700.    } -underline 0 -accelerator "Ctrl-G"
  1701. menu .mbar.options.menu -tearoff 0
  1702.    .mbar.options.menu add checkbutton -label "Autocommit Pages" \
  1703.       -variable gb_page_autocommit
  1704.  
  1705. # Create the menu
  1706. tk_menuBar .mbar .mbar.file .mbar.edit .mbar.format \
  1707.    .mbar.justify .mbar.page .mbar.navigate
  1708.  
  1709. ###############################################################
  1710. # Create the page label
  1711. set frame [frame .name_fr -relief groove -borderwidth $RIDGE_BORDER]
  1712. label $frame.label -text "Page Label"
  1713. entry $frame.name -width 25 -state disabled
  1714. button $frame.save -text Save -command {MH_SaveHelpPage}
  1715. $frame.save configure -state disabled -disabledforeground ""
  1716. button $frame.open -text "..." -command {
  1717.    if {$gb_current_page_changed == 0 || $gb_page_autocommit == 1} {
  1718.       MH_SaveHelpPage
  1719.       MH_SelectHelpPage FULL
  1720.    } else {
  1721.       if ![MH_QuestionDialog . "Help text on this page has changed!" \
  1722.          "Discard Changes" "Cancel"] {
  1723.          MH_SelectHelpPage FULL
  1724.       }
  1725.    }
  1726. }
  1727. pack $frame.label $frame.name $frame.open $frame.save -side left \
  1728.    -fill x -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING
  1729. pack $frame -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING -fill x
  1730.  
  1731. ###############################################################
  1732. # Create the text widget
  1733. frame .fr -borderwidth $RIDGE_BORDER -relief groove
  1734. pack .fr -padx $DEFAULT_PADDING -pady $DEFAULT_PADDING -side top \
  1735.    -expand true -fill both
  1736. set gt_mini_help [MH_ScrolledText .fr.help 70 20 0]
  1737. $gt_mini_help configure -font $FONT_NORMAL -bg $TEXT_COLOUR -state \
  1738.    disabled
  1739. $gt_mini_help tag bind sel <3> {+MH_PopupMenu $gt_mini_help .mbar.format.menu}
  1740. $gt_mini_help tag bind sel <Control-3> {+MH_PopupMenu $gt_mini_help .mbar.edit.menu}
  1741. $gt_mini_help tag bind sel <Shift-3> {+MH_PopupMenu $gt_mini_help .mbar.justify.menu}
  1742. bind $gt_mini_help <KeyPress> {
  1743.    set gb_current_page_changed 1
  1744.    set gb_project_changed      1
  1745.    $frame.save configure -state normal
  1746. }
  1747. pack .fr.help -side top -anchor w
  1748.  
  1749. # Pop-up the open dialogue
  1750. MH_OpenProject
  1751.